package net.chasing.androidbaseconfig;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.database.CursorWindow;
import android.os.Build;
import android.webkit.WebView;

import androidx.multidex.MultiDex;

import com.danikula.videocache.HttpProxyCacheServer;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.header.ClassicsHeader;
import com.scwang.smart.refresh.layout.SmartRefreshLayout;

import net.chasing.androidbaseconfig.util.AppUtils;
import net.chasing.androidbaseconfig.util.FileUtils;
import net.chasing.androidbaseconfig.util.L;
import net.chasing.androidbaseconfig.util.bugfixed.FixMemLeak;
import net.chasing.androidbaseconfig.util.thread.ComparableRunnable;
import net.chasing.androidbaseconfig.util.thread.ThreadPoolUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

import io.reactivex.rxjava3.plugins.RxJavaPlugins;

public class BaseApplication extends Application {
    public static BaseApplication INSTANCE;

    static {
        //设置RefreshLayout全局的Header构建器
        SmartRefreshLayout.setDefaultRefreshHeaderCreator((context, layout) -> {
            ClassicsHeader.REFRESH_HEADER_PULLING = context.getString(R.string.base_refresh_header_pulling);
            ClassicsHeader.REFRESH_HEADER_REFRESHING = context.getString(R.string.base_refresh_header_refreshing);
            ClassicsHeader.REFRESH_HEADER_LOADING = context.getString(R.string.base_refresh_header_loading);
            ClassicsHeader.REFRESH_HEADER_RELEASE = context.getString(R.string.base_refresh_header_release);
            ClassicsHeader.REFRESH_HEADER_FINISH = context.getString(R.string.base_refresh_header_finish);
            ClassicsHeader.REFRESH_HEADER_FAILED = context.getString(R.string.base_refresh_header_failed);
            ClassicsHeader.REFRESH_HEADER_UPDATE = context.getString(R.string.base_refresh_header_update);
            return new ClassicsHeader(context);
        });
        //设置RefreshLayout全局的Footer构建器
        SmartRefreshLayout.setDefaultRefreshFooterCreator((context, layout) -> {
            ClassicsFooter.REFRESH_FOOTER_PULLING = context.getString(R.string.base_refresh_footer_pulling);
            ClassicsFooter.REFRESH_FOOTER_RELEASE = context.getString(R.string.base_refresh_footer_release);
            ClassicsFooter.REFRESH_FOOTER_LOADING = context.getString(R.string.base_refresh_footer_loading);
            ClassicsFooter.REFRESH_FOOTER_REFRESHING = context.getString(R.string.base_refresh_footer_refreshing);
            ClassicsFooter.REFRESH_FOOTER_FINISH = context.getString(R.string.base_refresh_footer_finish);
            ClassicsFooter.REFRESH_FOOTER_FAILED = context.getString(R.string.base_refresh_footer_failed);
            ClassicsFooter.REFRESH_FOOTER_NOTHING = context.getString(R.string.base_refresh_footer_nothing);
            return new ClassicsFooter(context);
        });
    }

    // region Video的缓存
    private HttpProxyCacheServer proxy;

    public static HttpProxyCacheServer getProxy(Context context) {
        BaseApplication app = (BaseApplication) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }

    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer.Builder(this)
                .maxCacheSize(1024 * 1024 * 1024)       // 1 Gb for cache
                .build();
    }
    // endregion

    public static boolean isOpenSystemPage;

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
        fixTimeAssetManagerTimeoutException();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        INSTANCE = this;

        ThreadPoolUtils.getInstance().execute(new ComparableRunnable() {
            @Override
            public void run() {
                //删除无用文件
                FileUtils.deleteOverTimeTempFile(getApplicationContext());

                //设置RxJava回调异常的处理，避免RxJava报异常----RxJava2 取消订阅后，抛出的异常无法捕获，导致程序崩溃
                RxJavaPlugins.setErrorHandler(throwable -> {
                });
            }
        });

        // 扩充数据库的字段长度，避免数据太长导致异常
        try {
            Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
            field.setAccessible(true);
            field.set(null, 100 * 1024 * 1024); //the 100MB is the new size
        } catch (Exception e) {
            L.e(e.getMessage());
        }
    }

    // 不确定某些第三方库的初始化是否涉及隐私问题，所以统一放到用户确认授权隐私获取之后再进行初始化
    public void initWithCheckFirstIn() {
        FixMemLeak.fixLeak(this);

        // 解决AndroidP以上WebView多进程崩溃问题解决策略 (涉及隐私：获取应用列表)
        setWebViewPath();
    }

    private void setWebViewPath() {
        //应用运行列表AppUtils.getProcessName(base);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            String processName = AppUtils.getProcessName(getApplicationContext());
            String packageName = getApplicationContext().getPackageName();
            if (processName != null && !packageName.equals(processName)) {
                try {
                    WebView.setDataDirectorySuffix(processName);
                } catch (Exception ignored) {
                }
            }
        }
    }

    //android.os.BinderProxy.finalize() timed out after 120 seconds问题解决：
    private static void fixTimeAssetManagerTimeoutException() {
        try {
            Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");
            @SuppressLint("DiscouragedPrivateApi") Field field = clazz.getDeclaredField("INSTANCE");
            field.setAccessible(true);
            Object watchdog = field.get(null);
            try {
                if (clazz.getSuperclass() != null) {
                    Field thread = clazz.getSuperclass().getDeclaredField("thread");
                    thread.setAccessible(true);
                    thread.set(watchdog, null);
                }
            } catch (Exception t) {
                L.e(t);
                try {
                    // 直接调用stop方法，在Android 6.0之前会有线程安全问题
                    Method method = Objects.requireNonNull(clazz.getSuperclass()).getDeclaredMethod("stop");
                    method.setAccessible(true);
                    method.invoke(watchdog);
                } catch (Exception e) {
                    L.e(e);
                }
            }
        } catch (Exception t) {
            L.e(t);
        }
    }
}
